# -*- coding: utf-8 -*-


import numpy as np
import scipy.cluster.vq as vq
from server_placement.server_placement_basic import ServerPlacementBasic

class ServerPlacementKmeans(ServerPlacementBasic):
    
    """
    By means of K-means cluster, we assign the servers to the cluster according to the size of the cluster
    """
    
    def __init__(self, location, cluster_num, flow_list, compute_num):
        """
        
        param
        ----------
            compute_num : int
                the number of the servers we want to assign
            location : list
                the list to store both the lantitude and longtitude information of the location
                structure : [[content1],[content2],......,[contentn]]
                content ---> [lantitude,longitude]
            flow_list : list
                store the information about the load
            cluster_num : int
                the number of the clusters
        """
        ServerPlacementBasic._init_(self, compute_num)
        self.location = location
        self.flow_list = flow_list
        self.cluster_num = cluster_num
        
    def server_placement(self):
        """server_placement with the k_means
        
        param
        ----------
            we use the param in the init
            
        return
        ----------
            list_final : list
                store the information of the cluster center
            final_arrange : list
                final server distribution
        """
        centroid, label = vq.kmeans2(self.location, self.cluster_num, iter=2000)
        
        loca_array = np.array(self.location)
        flow_array = np.array(self.flow_list)
        centroid_array = np.array(centroid)
        list_final = []
        list_flow = []
        index_0 = []
        
        for index in range(self.cluster_num):
            loca_index = [i for i,x in enumerate(label) if x == index]
            if len(loca_index) == 0:
                continue
            location_incluster = loca_array[loca_index]
            flow_incluster = list(flow_array[loca_index])
            list_flow.append(sum(flow_incluster))
            center_index = centroid_array[index]
            center_all = np.ones((len(location_incluster),1)) * center_index
            base_distance = self.array_calculate_distance(center_all, location_incluster)
            distance_sort_index = np.argsort(base_distance)
            distance_near_index = distance_sort_index[0]
            cen_index = loca_index[distance_near_index]
            index_0.append(cen_index)
            location_center = list(location_incluster[distance_near_index])
            list_final.append(location_center)
            
        array_flow = np.array(list_flow) / sum(list_flow)
        compute_arrange = list(np.round(self.compute_num * array_flow))
        final_arrange = np.zeros((len(self.location), 1))
        final_arrange[index_0,0] = np.array(compute_arrange)
        final_arrange = np.transpose(final_arrange)
        final_arrange = list(final_arrange[0])
        
        return list_final, final_arrange